using System;
using System.Collections.Generic;
using System.Text;
using SharpMud.Server.App;
using SharpMud.Server.Systems;
using SharpMud.MudLib.Common.Environment;
using SharpMud.MudLib.Common.Resourcing;
using SharpMud.MudLib.Common.Entities.Players;
using SharpMud.Server.Systems.Net.Telnet;
using SharpMud.MudLib.Common.Entities.Players.Session;

namespace SharpMud.MudLib.Common
{
    public abstract class BaseMudLibRoot<TAreaInstance,TPlayerInstance> : SharpMud.Server.App.Application, IBaseMudLibRoot where TPlayerInstance : IPlayerCharacter, new() where TAreaInstance : IArea, new()
    {
        private static new readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType);

        #region Private Variables
        private TelnetServer<TelnetPlayerSession>                        _TelnetServer;
        private EnvironmentManager<TAreaInstance>   _EnvironmentManager;
        private PlayerManager<TPlayerInstance>      _PlayerManager;

        private PrivateResourcingHelper             _ResourcingHelper;
        #endregion

        protected BaseMudLibRoot()
        {
        }

        #region Important (Optional) Overrides

        protected override void __Pulse()
        {
            base.__Pulse();
            System.GC.Collect();
        }

        protected override void __Initialize()
        {
            base.__Initialize();

            this.LoadConfiguration();
            this._ResourcingHelper = new PrivateResourcingHelper(new Uri("sharpmud://" + this._Configuration.MudName + "/",UriKind.Absolute));


            //this._Configuration.MudTimeConfig.GoGlobal();
            //this.MudTimeSystem = new SharpMud.MudLib.Core.Time.MudTimeSystem(this._Configuration.MudTimeConfig);
            //this.MudTimeSystem.GoGlobal();

            //this.ScriptManager = new SharpMud.MudLib.Core.Scripting.ScriptManager();
            //this.ScriptManager.Initialize(this);

            //this.CommandManager = new SharpMud.MudLib.SAMPLE.Commands.CommandManager(this._Configuration.CommandManagerConfig);
            //this.CommandManager.Initialize(this);

            _PlayerManager = new PlayerManager<TPlayerInstance>(this.Configuration.PlayerManager);
            _PlayerManager.Initialize(this);
            RegisterServerSystem(_PlayerManager);

            this._EnvironmentManager = new Environment.EnvironmentManager<TAreaInstance>(this.Configuration.EnvironmentManager);
            this._EnvironmentManager.Initialize(this);
            this._ResourcingHelper.AddResourceProxy((IGuidIdentifiedResourceHost)_EnvironmentManager);
            this._ResourcingHelper.AddResourceProxy((IUriIdentifiedResourceHost)_EnvironmentManager);
            RegisterServerSystem(_EnvironmentManager);

            this._TelnetServer = new Server.Systems.Net.Telnet.TelnetServer<TelnetPlayerSession>();
            this._TelnetServer.LoadConfiguration(this.Configuration.TelnetServer);
            this._TelnetServer.Initialize(this);
            RegisterServerSystem(_TelnetServer);
        }

        protected override void __PreStart()
        {
            //this.MudTimeSystem.Enabled = true;

            //this.CommandManager.Start();

            this.PlayerManager.Start();

            this.TelnetServer.Start();
        }

        protected override void __PreStop()
        {
            //Shutdown the telnet server
            this.TelnetServer.Stop();
            this.TelnetServer.Dispose();
            this._TelnetServer = null;
            ////Shutdown the time system...well...stopping it
            //this.MudTimeSystem.Enabled = false;
            //Stop the environment system
            this.EnvironmentManager.Stop();
            ////Shutdown the Command Manager
            //this.CommandManager.Stop();
            ////Shutdown the Script Manager
            //this.ScriptManager = null;
            ////Shutdown the Player Manager
            //this.PlayerSystem.Players.CloseAllPlayers(true);
            //this.PlayerSystem.Shutdown();
        }
        protected override void __PostStop()
        {
            //It *mght* have already been done by an external call...
            //but it won't hurt to do it again...
            //(Some shutting down subsystems make config changes)
            SaveConfiguration();
        }

        protected override void __PrePause()
        {
            ////This pauses the server activity time tracker
            ////and it prevents *mud* time from advancing
            //this.MudTimeSystem.Enabled = false;

            this.TelnetServer.Pause();
        }

        protected override void __PreResume()
        {
            ////This resumes the server activity time tracker
            //this.MudTimeSystem.Enabled = true;

            this.TelnetServer.Resume();
        }

        #endregion

        #region Configuration
        protected BaseMudLibConfiguration<TAreaInstance,TPlayerInstance> _Configuration;
        protected virtual string DefaultConfigurationFile
        {
            get
            {
                return @"SharpMud.MudLib.Common.config";
            }
        }
        public BaseMudLibConfiguration<TAreaInstance, TPlayerInstance> Configuration
        {
            get
            {
                return _Configuration;
            }
        }
        public override void LoadConfiguration()
        {
            string cfn = Application.GetSubfileIntelligently(
                RootConfigurationFolder, DefaultConfigurationFile);
            System.IO.FileStream fs;
            System.Xml.Serialization.XmlSerializer xs;

            log.Info("Loading mudlib configuration...");
            try
            {
                xs = new System.Xml.Serialization.XmlSerializer(
                    typeof(BaseMudLibConfiguration<TAreaInstance, TPlayerInstance>));
            }
            catch (System.NotSupportedException e)
            {
                log.Warn("NotSupportedException thrown while creating application configuration serializer", e);
                log.Warn("Using DEFAULT configuration");
                this.LoadDefaultConfiguration();
                return;
            }
            try
            {
                fs = new System.IO.FileStream(cfn, System.IO.FileMode.Open);
            }
            catch (System.IO.FileNotFoundException e)
            {
                log.Warn("Mudlib configuration file not found",e);
                log.Warn("Using DEFAULT configuration");
                LoadDefaultConfiguration();
                return;
            }
            catch (System.IO.DirectoryNotFoundException e)
            {
                log.Warn("MudLib configuration directory not found", e);
                log.Warn("Using DEFAULT configuration");
                //(Should enter some sort of "setup" mode here.)
                LoadDefaultConfiguration();
                return;
            }
            try
            {
                this._Configuration = (BaseMudLibConfiguration<TAreaInstance, TPlayerInstance>)xs.Deserialize(fs);
            }
            catch (System.NotSupportedException e)
            {
                log.Warn("NotSupportedException thrown while deserializing application configuration", e);
                log.Warn("Using DEFAULT configuration");
                this.LoadDefaultConfiguration();
                return;
            }
            fs.Close();
        }
        public void LoadDefaultConfiguration()
        {
            BaseMudLibConfiguration<TAreaInstance, TPlayerInstance> mlc;
            mlc = BaseMudLibConfiguration<TAreaInstance, TPlayerInstance>.Default;
            this._Configuration = mlc;
        }
        public override void SaveConfiguration()
        {
            System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(
                typeof(BaseMudLibConfiguration<TAreaInstance, TPlayerInstance>)
                //				,
                //				new System.Type[] {typeof(DynamicTyping.TypeLocation),typeof(DynamicTyping.AssembliedTypeLocation) }
                );


            System.IO.Stream fs = new System.IO.FileStream(
                Application.GetSubfileIntelligently(RootConfigurationFolder, DefaultConfigurationFile),
                System.IO.FileMode.Create);

            xs.Serialize(fs, _Configuration);
            fs.Close();
        }
        #endregion

        public SharpMud.Server.App.IAppExecutionHandle GetAppExecHandle()
        {
            return base._GetAppExecHandle();
        }


        #region Required Overrides
        protected override Guid AppID
        {
            get { return _AppID; }
        }
        protected abstract Guid _AppID { get;}

        protected override string SecureAppKey
        {
            get { return Server.Systems.Security.Utility.MakeSecureKey(_AppID,SecureAppKey_Salt); }
        }
        protected abstract string SecureAppKey_Salt { get;}
        #endregion

        #region IGuidIdentifiedResourceHost Members

        public bool IsDefined(Guid guid)
        {
            return _ResourcingHelper.IsDefined(guid);
        }

        public object GetResource(Guid guid)
        {
            return _ResourcingHelper.GetResource(guid);
        }

        #endregion

        #region IUriIdentifiedResourceHost Members

        public Uri BaseUri
        {
            get { return _ResourcingHelper.BaseUri; }
        }

        public bool IsDefined(Uri resourceIndicator)
        {
            return _ResourcingHelper.IsDefined(resourceIndicator);
        }

        public object GetResource(Uri resourceIndicator)
        {
            return _ResourcingHelper.GetResource(resourceIndicator);
        }

        #endregion

        #region IBaseMudLibRoot Members

        public AppStatus ServerStatus
        {
            get { return this._Status; }
        }

        public SharpMud.MudLib.Common.Entities.Players.IPlayerManager PlayerManager
        {
            get { return (IPlayerManager)this._PlayerManager; ; }
        }

        public IEnvironmentManager EnvironmentManager
        {
            get { return (IEnvironmentManager)this._EnvironmentManager; }
        }

        public SharpMud.Server.Systems.Net.Telnet.TelnetServer<TelnetPlayerSession> TelnetServer
        {
            get { return this._TelnetServer; }
        }

        string IBaseMudLibRoot.GetSubfolderIntelligently(string parentFolder, string possibleSubfolder)
        {
            return SharpMud.Server.App.Application.GetSubfolderIntelligently(parentFolder, possibleSubfolder);
        }
        string IBaseMudLibRoot.GetSubfolderIntelligently(string parentFolder, params string[] possibleSubfolders)
        {
            return SharpMud.Server.App.Application.GetSubfolderIntelligently(parentFolder, possibleSubfolders);
        }
        string IBaseMudLibRoot.GetSubfileIntelligently(string parentFolder, string possibleSubfile)
        {
            return SharpMud.Server.App.Application.GetSubfileIntelligently(parentFolder, possibleSubfile);
        }
        #endregion

    }
}
